// Ease and Wizz 2.5.3 : Back Out, then Expo In
// Ian Haigh (http://aescripts.com/ease-and-wizz/)
// Last built: 2017-08-08T09:11:05+10:00

function doIt() {
  // you can manually edit the easing types here, e.g. "e.backIn", "e.expoOut" etc

  var ew_one = backOut;  // edit this one for first two keyframes
  var ew_two = expoIn;  // edit this one for last two

  // full list of easing types for reference:

  // backIn, backOut, backInOut
  // bounceOut, bounceIn, bounceInOut
  // circIn, circOut, circInOut
  // elasticIn, elasticOut, elasticInOut
  // expoIn, expoOut, expoInOut
  // quadIn, quadOut, quadInOut
  // quartIn, quartOut, quartInOut
  // quintIn, quintOut, quintInOut
  // sineIn, sineOut, sineInOut

  var n = 0;
  if (numKeys > 0) {
    n = nearestKey(time).index;

    if (key(n).time > time) { n-- }
    if (n < 2) { easingEquation = ew_one }
      // it's the start of the animation (keys 1 & 2)
    else if (n >= (numKeys - 1)) { easingEquation = ew_two }
      // it's the end of the animation (keys n-1 and n)
    else {return null}
       // otherwise, just use existing easing values on the keyframes
  }

  try {
    var key1 = key(n);
    var key2 = key(n+1);
  } catch(e) {
    return null;
  }

  // determine how many dimensions the keyframes need
  var dim = 1; // It's gotta have at least ONE dimension
  try {
    key(1)[1];
    dim = 2;
    key(1)[2];
    dim = 3;
  } catch(e) {}

  var t = time - key1.time;
  var d = key2.time - key1.time;

  var sX = key1[0];
  var eX = key2[0] - key1[0];

  if (dim >= 2) {
    var sY = key1[1];
    var eY = key2[1] - key1[1];

    if (dim >= 3) {
      var sZ = key1[2];
      var eZ = key2[2] - key1[2];
    }
  }

  if ((time < key1.time) || (time > key2.time)) {
    return value;
  } else {
    val1 =  easingEquation(t, sX, eX, d);
    switch (dim) {
      case 1:
         return val1;
         break;
      case 2:
         val2 = easingEquation(t, sY, eY, d);
         return [val1, val2];
         break;
      case 3:
         val2 = easingEquation(t, sY, eY, d);
         val3 = easingEquation(t, sZ, eZ, d);
         return [val1, val2, val3];
         break;
      default:
         return null;
    }
  }
}

// fixes for the expo glitch
var IN_EXPO_CORRECTION= 0.000976563;
var OUT_EXPO_CORRECTION  = 1.000976563;

var s = 1.70158; // "back" overshoot amount
var p = 0.81;  // period
var a = 50;  // amplitude

function bounceOut(t,b,c,d) {
  if ((t/=d) < (1/2.75)) { return c*(7.5625*t*t) + b }
  else if (t < (2/2.75)) { return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b }
  else if (t < (2.5/2.75)) { return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b }
  else { return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b }
}
function bounceIn(t, b, c, d) {
  return c - bounceOut (d-t, 0, c, d) + b;
}
function bounceInOut(t, b, c, d) {
  if (t < d/2) return bounceIn (t*2, 0, c, d) * .5 + b;
  else return bounceOut (t*2-d, 0, c, d) * .5 + c*.5 + b;
}
function backIn(t, b, c, d) {
  return c*(t/=d)*t*((s+1)*t - s) + b;
}
function backInOut(t, b, c, d) {
  if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
  return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
}
function backOut(t, b, c, d) {
  return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
}
function circIn(t, b, c, d) {
  return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
}
function circInOut(t, b, c, d) {
  if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
  return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
}
function circOut(t, b, c, d) {
  return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
}
function elasticIn(t, b, c, d) {
  if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
  if (!a || a < Math.abs(c)) { a=c;  s=p/4; }
  else  s = p/(2*Math.PI) * Math.asin (c/a);
  return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
}
function elasticInOut(t, b, c, d) {
  if (t==0) return b;  if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
  if (!a || a < Math.abs(c)) { a=c;  s=p/4; }
  else s = p/(2*Math.PI) * Math.asin (c/a);
  if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
  return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
}
function elasticOut(t, b, c, d) {
  if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
  if (!a || a < Math.abs(c)) { a=c; s=p/4; }
  else s = p/(2*Math.PI) * Math.asin (c/a);
  return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b);
}
function expoIn(t, b, c, d) {
  return t==0 ? b : c * (Math.pow(2, 10 * (t/d - 1)) - IN_EXPO_CORRECTION) + b;
}
function expoInOut(t, b, c, d) {
  var v;
  if ((t/=d/2) < 1) {
    v = Math.pow(2, 10 * (t - 1)) - IN_EXPO_CORRECTION;
  } else {
    v = (-Math.pow(2, -10 * (t - 1)) + 2) + IN_EXPO_CORRECTION;
  }
  return b + (v/2) * c;
}
function expoOut(t, b, c, d) {
  return (t==d) ? b+c : c * OUT_EXPO_CORRECTION * (-Math.pow(2, -10 * t/(d)) + 1) + b;
}
function quadIn(t, b, c, d) {
  return c*(t/=d)*t + b;
}
function quadInOut(t, b, c, d) {
  if ((t/=d/2) < 1) return c/2*t*t + b;
  return -c/2 * ((--t)*(t-2) - 1) + b;
}
function quadOut(t, b, c, d) {
  return -c *(t/=d)*(t-2) + b;
}
function quartIn(t, b, c, d) {
  return c*(t/=d)*t*t*t + b;
}
function quartInOut(t, b, c, d) {
  if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
  return -c/2 * ((t-=2)*t*t*t - 2) + b;
}
function quartOut(t, b, c, d) {
  return -c * ((t=t/d-1)*t*t*t - 1) + b;
}
function quintIn(t, b, c, d) {
  return c*(t/=d)*t*t*t*t + b;
}
function quintInOut(t, b, c, d) {
  if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
  return c/2*((t-=2)*t*t*t*t + 2) + b;
}
function quintOut(t, b, c, d) {
  return c*((t=t/d-1)*t*t*t*t + 1) + b;
}
function sineIn(t, b, c, d) {
  return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
}
function sineInOut(t, b, c, d) {
  return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
}
function sineOut(t, b, c, d) {
  return c * Math.sin(t/d * (Math.PI/2)) + b;
}

(doIt() || value);
